package org.hikari.qqbot.xiuxian.task.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.hikari.qqbot.xiuxian.command.CommandExecutionInfo;
import org.hikari.qqbot.xiuxian.command.ICommand;
import org.hikari.qqbot.xiuxian.command.standard.xiulian.*;
import org.hikari.qqbot.xiuxian.service.bo.UserSetting;
import org.hikari.qqbot.xiuxian.task.TaskParams;
import org.hikari.qqbot.xiuxian.task.TypedITask;
import org.hikari.qqbot.xiuxian.task.UserTaskRuntime;
import org.hikari.qqbot.xiuxian.util.BizUtil;
import org.hikari.qqbot.xiuxian.util.MessageUtil;
import org.hikari.qqbot.xiuxian.util.TimedCache;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * created at 2024-12-19 22:14:46
 *
 * @author yinchao
 * @version 1.0
 **/
@Slf4j
@Component
public class ShuangXiuTask extends TypedITask<ShuangXiuTask.Config> {

    @Getter
    @Setter
    @ToString
    public static class Config {

        // 道侣最大等待间隔
        private int daoLvWaitMinutes = 30;
        // 道侣重试间隔
        private int daoLvRetryMinutes = 5;
        // 双修用户游戏id
        private String shuangXiuGameId;
        // 是否是道侣双修
        private boolean daoLvShuangXiu = false;
        // 是否是被动方
        private boolean passive = false;
        // 自动提升境界
        private boolean autoLvlUp = true;
        // 双修次数
        private int shangXiuTimes = 20;
        // 双修无响应或者失败打坐次数
        private int fallbackDaZuoTimes = 10;
        // 打坐平均分钟
        private float daZuoAvgMinutes = 8f;
        // 聊天群id
        private Long chatGroupId;

    }

    @Override
    public String getId() {
        return "双修";
    }

    @Override
    public ICommand initCommand(UserSetting setting) {
        return new XiShouLingLiCommand();
    }

    @Override
    public Collection<ICommand> process(UserTaskRuntime runtime, String message) {
        Collection<ICommand> commands = doProcess(runtime, message);
        if (commands == null || commands.isEmpty()) {
            return null;
        }
        UserSetting setting = runtime.getUserSetting();
        Config config = config(setting);
        for (ICommand command : commands) {
            command.groupId(config.getChatGroupId());
        }
        return commands;
    }

    private List<ICommand> doProcess(UserTaskRuntime runtime, String message) {
        UserSetting setting = runtime.getUserSetting();
        Config config = config(setting);

        if (message.contains("你还没有打坐！")) {
            if (config.isPassive()) {
                log.info("[{} - {}] 当前用户为双修被动方, 未打坐状态不发送双修命令", setting.getUserId(), getId());
                return null;
            }
            return List.of(buildShuangXiuCommand(config, runtime.getMeta()));
        }

        if (message.contains("打坐中")) {
            runtime.getMeta().remove(TaskParams.shuangXiuWaitDeathTime);
            Date sendTime = MessageUtil.parseExpectTime(message);
            if (sendTime != null) {
                return List.of(new XiShouLingLiCommand().delay(sendTime));
            }
        }

        if (message.contains("一起道侣双修中") || message.contains("一起双修中") || message.contains("你正在双修中")) {
            runtime.getMeta().remove(TaskParams.shuangXiuWaitDeathTime);
            Date sendTime = MessageUtil.parseExpectTime(message);
            if (sendTime != null) {
                return List.of(new XiShouLingLiCommand().delay(sendTime));
            }
        }

        if (message.contains("不想和你一起道侣双修") || message.contains("不想和你一起双修")) {
            // 设置被拒绝状态
            runtime.getMeta().set(TaskParams.shuangXiuRejected, true);
            return null;
        }

        if (message.contains("你有待处理的道侣双修") || message.contains("你有待处理的双修")) {
            return List.of(buildTongYiShuangXiuCommand(config, runtime));
        }

        if (message.contains("没找到你要同意的道侣双修请求")) {
            return List.of(buildShuangXiuCommand(config, runtime.getMeta()));
        }

        if (message.contains("吸收灵力成功")) {
            runtime.getMeta().remove(TaskParams.shuangXiuWaitDeathTime);
            List<ICommand> commands = new ArrayList<>(2);
            if (config.isAutoLvlUp() && message.contains("可以提升境界了") && !message.contains("金丹不足")) {
                commands.add(new YiJianTiShengJingJieCommand());
            }
            Boolean p = runtime.getMeta().get(TaskParams.shuangXiuPassiveParty);
            if ((p != null && p) || config.isPassive()) {
                log.info("[{} - {}] 当前为双修被动方，吸收灵力后不发送双修请求", setting.getUserId(), getId());
                return commands;
            }
            commands.add(buildShuangXiuCommand(config, runtime.getMeta()));
            return commands;
        }

        if (message.contains("想和你一起道侣双修，你愿意吗") || message.contains("想和你一起双修，你愿意吗")) {
            // 获取当前任务上次执行的命令
            CommandExecutionInfo command = runtime.getMeta().getTaskLastCommandInfo(getId());
            if (command != null) {
                // 如果上一次指令包含[道侣双修]，说明该指令是当前用户发送的，那么不需要处理
                if (isShuangXiuCommand(command.getCommand())) {
                    Boolean rejected = runtime.getMeta().get(TaskParams.shuangXiuRejected);
                    // 如果没有被拒绝过
                    if (rejected == null || !rejected) {
                        log.info("[{} - {}] 上一次发送的指令是[{}] 不需要同意双修请求", setting.getUserId(), getId(), command.getCommand());
                        return null;
                    }
                }
            }
            // 清理等待时间
            return List.of(buildTongYiShuangXiuCommand(config, runtime));
        }

        if (message.contains("请对方先吸收上次的灵力，再来道侣双修！")) {
            TimedCache<Date> deathTimeCache = runtime.getMeta().getTimed(TaskParams.shuangXiuWaitDeathTime);
            Date deathTime = deathTimeCache.getValue();
            // 第一次的时候先等待对方
            Date now = new Date();
            if (deathTime == null) {
                // 到期时间
                deathTime = DateUtil.offsetMinute(now, config.getDaoLvWaitMinutes());
                runtime.getMeta().setTimed(TaskParams.shuangXiuWaitDeathTime, deathTime, DateUtil.offsetMinute(now, config.getDaoLvWaitMinutes() + config.getDaoLvRetryMinutes()));
                Date nextTime = DateUtil.offsetMinute(now, config.getDaoLvRetryMinutes());
                log.info("[{} - {}] 对方还没有吸收灵力, 等待{}分钟, 下次双修发起时间: {} 到期时间: {}", setting.getUserId(), getId(), config.getDaoLvRetryMinutes(), MessageUtil.getDisplaySendTime(nextTime), deathTime);
                return List.of(buildShuangXiuCommand(config, runtime.getMeta()).delay(nextTime));
            } else {
                if (now.after(deathTime)) {
                    log.info("[{} - {}] 已经等待{}分钟, 对方仍然没有吸收灵力 先进行打坐{}连", setting.getUserId(), getId(), config.getDaoLvWaitMinutes(), config.getFallbackDaZuoTimes());
                    return List.of(new DaZuoCommand().times(config.getFallbackDaZuoTimes()));
                } else {
                    Date nextTime = DateUtil.offsetMinute(now, config.getDaoLvRetryMinutes());
                    if (nextTime.after(deathTime)) {
                        nextTime = deathTime;
                    }
                    log.info("[{} - {}] 对方还没有吸收灵力, 等待{}分钟, 等待到期时间: {} 下次双修发起时间: {}", setting.getUserId(), getId(), config.getDaoLvRetryMinutes(), MessageUtil.getDisplaySendTime(deathTime), MessageUtil.getDisplaySendTime(nextTime));
                    return List.of(buildShuangXiuCommand(config, runtime.getMeta()).delay(nextTime));
                }
            }
        }

        if (message.contains("TA的总体力次数不足")) {
            Date sendTime = BizUtil.beginOfTomorrow();
            ICommand command = buildDaZuoCommand(runtime, config, sendTime);
            return List.of(command);
        }

        if (message.contains("对方正在打坐中！请等待打坐完成") || message.contains("对方正在双修中！请等待双修完成")) {
            Date sendTime = MessageUtil.parseExpectTime(message);
            if (sendTime != null) {
                ICommand command = buildDaZuoCommand(runtime, config, sendTime);
                return List.of(command);
            }
        }

        // 体力次数不足时，进行判断
        if (message.contains("需要消耗次数")) {
            Integer tiLiTimes = MessageUtil.parseTiLiTimes(message);
            if (tiLiTimes != null) {
                // 没有体力的时候，明天继续
                ICommand command;
                if (tiLiTimes == 0) {
                    command = buildShuangXiuCommand(config, runtime.getMeta()).delay(BizUtil.beginOfTomorrow());
                }
                // 降级为10连
                else if (tiLiTimes >= 10) {
                    command = buildShuangXiuCommand(config, runtime.getMeta(), 10);
                }
                // 降级为单次打坐
                else {
                    command = buildShuangXiuCommand(config, runtime.getMeta(), 1);
                }
                return List.of(command);
            }
        }

        return null;
    }

    private static boolean isShuangXiuCommand(String command) {
        return command.contains(DaoLvShuangXiuCommand.COMMAND) || command.contains(ShuangXiuCommand.COMMAND);
    }

    private ICommand buildDaZuoCommand(UserTaskRuntime runtime, Config config, Date sendTime) {
        Date now = new Date();
        // 如果预计发送时间小于当前时间， 那么直接发送
        if (now.after(sendTime)) {
            return buildShuangXiuCommand(config, runtime.getMeta());
        }

        int daZuoTimes = calcDaZuoTimes(now, sendTime, config);

        if (daZuoTimes == 0) {
            return buildShuangXiuCommand(config, runtime.getMeta()).delay(sendTime);
        }

        if (daZuoTimes >= config.getFallbackDaZuoTimes()) {
            return new DaZuoCommand().times(config.getFallbackDaZuoTimes());
        }

        // 次数小于10转化为单次打坐
        return new DaZuoCommand();
    }

    private int calcDaZuoTimes(Date now, Date sendTime, Config config) {
        // 计算相差的分钟数
        long minute = DateUtil.between(now, sendTime, DateUnit.MINUTE);
        // 计算预计打坐次数
        int daZuoTimes = BigDecimal.valueOf(minute)
                .divide(BigDecimal.valueOf(config.getDaZuoAvgMinutes()), 0, RoundingMode.HALF_UP)
                .intValue();
        log.info("根据对方完成时间({})，按照单次打坐{}分钟估算打坐次数为: {}", MessageUtil.getDisplaySendTime(sendTime), config.getDaZuoAvgMinutes(), daZuoTimes);
        return daZuoTimes;
    }

    private ICommand buildShuangXiuCommand(Config config, UserTaskRuntime.RuntimeMeta meta) {
        return buildShuangXiuCommand(config, meta, null);
    }

    private ICommand buildShuangXiuCommand(Config config, UserTaskRuntime.RuntimeMeta meta, Integer times) {
        int shuangXiuTimes = times == null ? config.getShangXiuTimes() : times;
        meta.remove(TaskParams.shuangXiuPassiveParty);
        meta.remove(TaskParams.shuangXiuRejected);
        if (config.isDaoLvShuangXiu()) {
            return new DaoLvShuangXiuCommand().times(shuangXiuTimes);
        } else {
            return new ShuangXiuCommand(config.getShuangXiuGameId()).times(shuangXiuTimes);
        }
    }

    private ICommand buildTongYiShuangXiuCommand(Config config, UserTaskRuntime runtime) {
        UserTaskRuntime.RuntimeMeta meta = runtime.getMeta();
        meta.remove(TaskParams.shuangXiuWaitDeathTime);
        meta.remove(TaskParams.shuangXiuRejected);
        meta.set(TaskParams.shuangXiuPassiveParty, true);

        // 清理队列中的道侣双修申请
        int count = runtime.getRunner().deleteCommandIf(cmd ->
                Objects.equals(cmd.getTaskId(), getId())
                        && isShuangXiuCommand(cmd.getCommand())
        );

        if (count > 0) {
            log.info("[{} - {}] 已同意对方的双修请求, 清理{}条队列中的道侣双修命令", runtime.getUserSetting().getUserId(), getId(), count);
        }

        if (config.isDaoLvShuangXiu()) {
            return new TongYiDaoLvShuangXiuCommand();
        } else {
            return new TongYiShuangXiuCommand();
        }

    }

}
